package pilas;

import java.util.Stack;
import javax.swing.JOptionPane;

/**
 *
 * @author D4y4
 */
public class pila {

    int tope;
    int numeroElementos;
    int topeAux;
    Object[] arrayPila2;
    boolean pasaDoble = false;
    Object[] arrayPila;//acepta cualquier tipo de informacion, numeros, letras
//Arreglo Prioridades
    String[] operadores = {"(,);[,];{,}", "^;radical", "*;/", "+;-"};
//    char[] operadores = {'(', '˄;radical', '*;/', '+;-'};

    public pila() {

    }

    /**
     * PASO NUMERO 1 Retorna l grado de la prioridad de un elemento y si no es
     * un operador retorna -1
     *
     * @return
     */
    public int getPrioridad(char operador_operando) {
//    String[] operadores = {"(,);[,];{,}", "˄", "*;/", "+;-"};
        int pos = -1;
        String posOperadores = "";
        int ascii = (int) operador_operando;//Transorma el caracter en codigo ascii nos ayudara para saber si 
//       http://www.ascii.cl/es/
        //algun dato esta ingresado  EJEMPLO:%""@}´ mal retorne -2 
        //VALIDOS
        //OPERADORES 40-43,45,47,91,(93-94,123,125)
        //NUMEROS 48-57
        //ALFABETO MAYUSCULAS 65-90
        //ALFABETO MINUSCULAS 97-122

        if ((ascii >= 48 && ascii <= 57) || (ascii >= 65 && ascii <= 90) || (ascii >= 97 && ascii <= 122) || (ascii >= 40 && ascii <= 43) || (ascii == 45 || ascii == 47 || ascii == 91 || ascii == 93 || ascii == 94 || ascii == 123 || ascii == 125)) {
            for (int i = 0; i < operadores.length; i++) {
                if (i == 0) {//Pósicion 0 s encuentra los operadores de apertura y cierre d una ecuacion
                    //Corchetes ,llaves ,parentesis
                    posOperadores = operadores[i];// "(,);[,];{,}" obtenemos los valores de la posicion 0
                    String totalParentesis[] = posOperadores.split(";"); //Obtenemos un arreglo de todos los operadores
                    //de apertura y cierre ya sea l caso:(,)=posicion 0;[,]=posicion 1;{,}=posicion 2
                    for (int j = 0; j < totalParentesis.length; j++) {
                        String aperturaCierreTotal = totalParentesis[j];
                        String aperturaCierre[] = aperturaCierreTotal.split(",");//Obtenemos un arreglo de todos los operadores
                        //de apertura y cierre ya sea l caso:( o [ o {=posicion 0;] o)o}=posicion 1
                        if (aperturaCierre[0].equals((String.valueOf(operador_operando))) || aperturaCierre[1].equals((String.valueOf(operador_operando)))) {
                            return 3; //encuentre cualqiera de las dos opciones ya sea apertura o cierre
                            //retorne i
                        }

                    }
                } else if (i == 1) {//RADICAL O POTENCIA
                    posOperadores = operadores[i];
                    String totalExpoRad[] = posOperadores.split(";"); //Obtenemos un arreglo de todos los operadores
                    //de tipo multiplicacion y division ya sea l caso:*=posicion 0;/=posicion 1
                    if (totalExpoRad[0].equals((String.valueOf(operador_operando))) || totalExpoRad[1].equals((String.valueOf(operador_operando)))) {
                        return 2; //encuentre cualqiera de las dos opciones ya sea potencia  radical
                    }
                } else if (i == 2) {//multiplicacion O division
                    posOperadores = operadores[i];
                    String totalMultipliDivi[] = posOperadores.split(";"); //Obtenemos un arreglo de todos los operadores
                    //de tipo multiplicacion y division ya sea l caso:*=posicion 0;/=posicion 1
                    if (totalMultipliDivi[0].equals((String.valueOf(operador_operando))) || totalMultipliDivi[1].equals((String.valueOf(operador_operando)))) {
                        return 1; //encuentre cualqiera de las dos opciones ya sea potencia  radical
                    }
                } else if (i == 3) {//suma  O resta
                    posOperadores = operadores[i];
                    String totalSumaResta[] = posOperadores.split(";"); //Obtenemos un arreglo de todos los operadores
                    //de tipo suma y resta   ya sea l caso:+=posicion 0;-=posicion 1
                    if (totalSumaResta[0].equals((String.valueOf(operador_operando))) || totalSumaResta[1].equals((String.valueOf(operador_operando)))) {
                        return 0; //encuentre cualqiera de las dos opciones ya sea potencia  radical
                    }
                }
            }
        } else {
            return -2;
        }

        return pos;
    }

    /**
     * Primer Paso
     */
    Stack<Character> pilaTemporalOperadores = new Stack<>();
    Stack<Character> pilaTemporalRespuesta = new Stack<>();
    char respuestaOperador = ' ';

    public Stack<Character> getPostfija(String datos) {
        datos = datos.trim();
//        empty nos permite saber si la pila esta vacia 
//peek devuelve el valor del primer elemento (lo hojea).  cima 
//pop saca el primer elemento y retorna su valor 
//push agrega un elemento a la pila 
//search busca el elemento recibido y retorna un entero con su posición (si no esta retorna -1) 
        Stack<Character> pilaRespuesta = new Stack<>();
//        pilaTemporalOperadores.push("");
        for (int i = 0; i < datos.length(); i++) {
            char dato = datos.charAt(i);
            int tipo = getPrioridad(dato);
            if (tipo == -1) {
                pilaRespuesta.push(dato);
            } else if (tipo == -2) {//algun dato mal ingresado caracter %
                pilaRespuesta.clear();
                return pilaRespuesta;
            } else if (tipo >= 0) {//Agregar l operador d acuerdo a las reglas a la pila
//                pilaRespuesta.push((String.valueOf(dato)));

                pilaTemporalRespuesta = Reglas(dato, tipo);
                if (!pilaTemporalRespuesta.empty()) {
                    for (int j = 0; j < pilaTemporalRespuesta.size(); j++) {
                        respuestaOperador = pilaTemporalRespuesta.get(j);
                        pilaRespuesta.push(respuestaOperador);
                    }

                }
                respuestaOperador = ' ';
                pilaTemporalRespuesta.clear();
            }
            if (i == datos.length() - 1) {//Algunos datos q dan sin apilar a la respuesta
                ///voy cogiendo los datos d abajo hacia arriba como los datos son segun su rango
                int decremento = pilaTemporalOperadores.size();
                if (!pilaTemporalOperadores.empty()) {
                    for (int j = 0; j < pilaTemporalOperadores.size(); j++) {
                        respuestaOperador = pilaTemporalOperadores.get(decremento - 1);
                        pilaRespuesta.push(respuestaOperador);
                        decremento--;
                    }
                }

            }

        }

        return pilaRespuesta;

    }
    char respuestaRegla = ' ';

    /**
     *
     * @param operador es con qien vamos a comparar su presedencia y ejecutar el
     * respectivo codigo retorna la respuesta si retorna vacio es por q no s
     * ejecuto un cierrre de operador }]) o d acuerdo al caso q haya estado
     * @param prioridad
     * @return
     */
    public Stack<Character> Reglas(char operador, int prioridad) {
        if (prioridad == 3) {//A la primera vez ninguna validacion d reglas
            if (isCierre(operador)) {
                char apertura = getApertura(operador);
                int posInicio = getPosicion(apertura);
                pilaTemporalOperadores.push(operador);
                int posfin = getPosicion(operador);

                for (int i = posInicio; i <= posfin; i++) {
                    char dato = pilaTemporalOperadores.get(i);
                    if (!(String.valueOf(dato).equals(String.valueOf(apertura)) || String.valueOf(dato).equals(String.valueOf(operador)))) {
                        pilaTemporalRespuesta.push(dato);
                    }
                }//desapilas los elementos q no se necesitan 
                for (int i = posInicio; i <= posfin; i++) {
                    pilaTemporalOperadores.pop();
                }
            } else {
                pilaTemporalOperadores.push(operador);
            }

        } else if (prioridad < 3) {
            if (!pilaTemporalOperadores.empty()) {//comparacion para saber si la pilaoPERADORES ESTA VACIA 
                //DEBIDO A Q si sta vacia no podemos sacar la presedencia

                char presedencia = presedencia();
                int prioridadPresedencia = getPrioridad(presedencia);
                if (prioridadPresedencia < 3) {
                    if (prioridad == prioridadPresedencia) {//0
                        respuestaRegla = pilaTemporalOperadores.lastElement();
                        pilaTemporalRespuesta.push(respuestaRegla);
                        int posfin = getPosicion(respuestaRegla);
                        pilaTemporalOperadores.remove(posfin);//UNA VES ENCONTRADO L OPERADOR
                        //LO REMUEVO Y APILO L NUEVO OPERADOR SUCESOR
                        pilaTemporalOperadores.push(operador);

                    }
                    if (prioridad > prioridadPresedencia) {//1
                        pilaTemporalOperadores.push(operador);
                    }
                    if (prioridad < prioridadPresedencia) {//2
                        int decremento = pilaTemporalOperadores.size();

                        for (int j = 0; j < pilaTemporalOperadores.size(); j++) {
                            char dato = pilaTemporalOperadores.get(decremento - 1);
                            pilaTemporalRespuesta.push(dato);
                            decremento--;
                        }
                        pilaTemporalOperadores.clear();
                        pilaTemporalOperadores.push(operador);
                    }
                } else {
                    pilaTemporalOperadores.push(operador);

                }
            } else {
                pilaTemporalOperadores.push(operador);
            }

        }
        return pilaTemporalRespuesta;

    }

    /**
     * retorna si el operador a comparar es de cierre
     *
     * @param operador
     * @return
     */
    public boolean isCierre(char operador) {
        boolean es_noes = false;
        switch (operador) {
            case ']':
                return true;
            case '}':
                return true;

            case ')':
                return true;

        }
        return es_noes;
    }

    /**
     *
     * @param operador ingresa el operador d apertura para luego retornar l d
     * cierre
     * @return
     */
    public char getApertura(char operador) {
        char apertura = '-';
//        (,);[,];{,}
        switch (operador) {
            case ']':
                return '[';
            case '}':
                return '{';
            case ')':
                return '(';
        }
        return apertura;
    }

    /**
     * obtiene la posicion de dicho operador
     *
     * @param operador el primero q encuentra lo retorna
     * @return
     */
    public int getPosicion(char operador) {
        int posApertura = -1;
        for (int i = 0; i < pilaTemporalOperadores.size(); i++) {
            if (operador == pilaTemporalOperadores.get(i)) {
                return i;
            }
        }
        return posApertura;

    }

    /**
     * peek devuelve el valor del primer elemento (lo hojea). cima aqlla es l
     * valor de presedencia pero antes d agregar elnuevo operador ala pila
     *
     * @return
     */
    public char presedencia() {

        char pre = pilaTemporalOperadores.peek();
        return pre;
    }

    public String getDatosPila(Stack<Character> pila) {
        String respuesta = "";

        for (int i = 0; i < pila.size(); i++) {
            respuesta += String.valueOf(pila.get(i));
        }

        return respuesta;
    }

    /**
     * paso 1 invertir 1+2*3=3*2+1
     *
     * @param cadena
     * @return
     */
    public String getInvertirCadena(String cadena) {
        if ((null == cadena) || (cadena.length() <= 1)) {
            return cadena;
        }
        char[] chars = cadena.toCharArray();
        int length = chars.length - 1;
        for (int i = 0; i < length; i++) {
            char tempVar = chars[i];
            chars[i] = chars[length];
            chars[length--] = tempVar;
        }
        return new String(chars);
    }

    /**
     *
     * @param operador ingresa el operador d apertura para luego retornar l d
     * cierre
     * @return
     */
    public char getCierre(char operador) {
        char apertura = ' ';
//        (,);[,];{,}
        switch (operador) {
            case '[':
                return ']';
            case '{':
                return '}';
            case '(':
                return ')';
        }
        return apertura;
    }

    /**
     * retorna si el operador a comparar es de cierre
     *
     * @param operador
     * @return
     */
    public boolean isAbrir(char operador) {
        boolean es_noes = false;
        switch (operador) {
            case '[':
                return true;
            case '{':
                return true;
            case '(':
                return true;

        }
        return es_noes;
    }

    public Stack<Character> ReglasPrefija(char operador, int prioridad) {
        if (prioridad == 3) {//A la primera vez ninguna validacion d reglas
            if (isAbrir(operador)) {
                char apertura = getCierre(operador);
                int posInicio = getPosicion(apertura);
                pilaTemporalOperadores.push(operador);
                int posfin = getPosicion(operador);

                for (int i = posInicio; i <= posfin; i++) {
                    char dato = pilaTemporalOperadores.get(i);
                    if (!(String.valueOf(dato).equals(String.valueOf(apertura)) || String.valueOf(dato).equals(String.valueOf(operador)))) {
                        pilaTemporalRespuesta.push(dato);
                    }
                }//desapilas los elementos q no se necesitan 
                for (int i = posInicio; i <= posfin; i++) {
                    pilaTemporalOperadores.pop();
                }
            } else {
                pilaTemporalOperadores.push(operador);
            }

        } else if (prioridad < 3) {
            if (!pilaTemporalOperadores.empty()) {//comparacion para saber si la pilaoPERADORES ESTA VACIA 
                //DEBIDO A Q si sta vacia no podemos sacar la presedencia

                char presedencia = presedencia();
                int prioridadPresedencia = getPrioridad(presedencia);
                if (prioridadPresedencia < 3) {
                    if (prioridad == prioridadPresedencia) {//0
                        respuestaRegla = pilaTemporalOperadores.lastElement();
                        pilaTemporalRespuesta.push(respuestaRegla);
                        int posfin = getPosicion(respuestaRegla);
                        pilaTemporalOperadores.remove(posfin);//UNA VES ENCONTRADO L OPERADOR
                        //LO REMUEVO Y APILO L NUEVO OPERADOR SUCESOR
                        pilaTemporalOperadores.push(operador);

                    }
                    if (prioridad > prioridadPresedencia) {//1
                        pilaTemporalOperadores.push(operador);
                    }
                    if (prioridad < prioridadPresedencia) {//2
                        int decremento = pilaTemporalOperadores.size();

                        for (int j = 0; j < pilaTemporalOperadores.size(); j++) {
                            char dato = pilaTemporalOperadores.get(decremento - 1);
                            pilaTemporalRespuesta.push(dato);
                            decremento--;
                        }
                        pilaTemporalOperadores.clear();
                        pilaTemporalOperadores.push(operador);
                    }
                } else {
                    pilaTemporalOperadores.push(operador);

                }
            } else {
                pilaTemporalOperadores.push(operador);
            }

        }
        return pilaTemporalRespuesta;

    }

    public Stack<Character> getPrefija(String datos) {
        datos = datos.trim();
//        empty nos permite saber si la pila esta vacia 
//peek devuelve el valor del primer elemento (lo hojea).  cima 
//pop saca el primer elemento y retorna su valor 
//push agrega un elemento a la pila 
//search busca el elemento recibido y retorna un entero con su posición (si no esta retorna -1) 
        Stack<Character> pilaRespuesta = new Stack<>();
//        pilaTemporalOperadores.push("");
        for (int i = 0; i < datos.length(); i++) {
            char dato = datos.charAt(i);
            int tipo = getPrioridad(dato);
            if (tipo == -1) {
                pilaRespuesta.push(dato);
            } else if (tipo == -2) {//algun dato mal ingresado caracter %
                pilaRespuesta.clear();
                return pilaRespuesta;
            } else if (tipo >= 0) {//Agregar l operador d acuerdo a las reglas a la pila
//                pilaRespuesta.push((String.valueOf(dato)));

                pilaTemporalRespuesta = ReglasPrefija(dato, tipo);
                if (!pilaTemporalRespuesta.empty()) {
                    for (int j = 0; j < pilaTemporalRespuesta.size(); j++) {
                        respuestaOperador = pilaTemporalRespuesta.get(j);
                        pilaRespuesta.push(respuestaOperador);
                    }

                }
                respuestaOperador = ' ';
                pilaTemporalRespuesta.clear();
            }
            if (i == datos.length() - 1) {//Algunos datos q dan sin apilar a la respuesta
                ///voy cogiendo los datos d abajo hacia arriba como los datos son segun su rango
                int decremento = pilaTemporalOperadores.size();
                if (!pilaTemporalOperadores.empty()) {
                    for (int j = 0; j < pilaTemporalOperadores.size(); j++) {
                        respuestaOperador = pilaTemporalOperadores.get(decremento - 1);
                        pilaRespuesta.push(respuestaOperador);
                        decremento--;
                    }
                }

            }

        }

        return pilaRespuesta;

    }

}
